package it.conv;

public class Encoder {
	
	private int M;
	private int out;
	private int lung_canale;

	//Parametro K del codificatore convoluzionale
	private int KAPPA;
	//Polinomio generatore
	private int[][] poli;
	
	private int[] arrayNonCodificato;
	
	private int[] shiftRegister;
	
	private int[] xor; //Porte XOR	
	
	public Encoder(int[] input, int m, int[][] p, int out, int l) {
		
		M = m;
		KAPPA = M - 1;
		poli = p;
		this.out = out;
		lung_canale = (l + M - 1) * this.out;
		
		//Porte XOR pari al numero di bit di output
		xor = new int[this.out];
		
		//Allocazione del messaggio codificato
		arrayNonCodificato = new int[input.length + KAPPA];
		for (int i = 0; i < input.length; i++)
			arrayNonCodificato[i] = input[i];
		for (int i = 0; i < KAPPA; i++)
			arrayNonCodificato[input.length + i] = 0;
		
		//Inizializzazione delle memorie
		shiftRegister = new int[M];
		for (int i = 0; i < shiftRegister.length; i++)
			shiftRegister[i] = 0;
			
	}
	
	public int[] encode() {
	
		/* 
		 * Lo Shift Register opera come un buffer circolare, quindi necessita di
	     * un puntatore sulla testa. Non necessita anche di un puntatore sulla coda,
	     * poichè non vogliamo prendere altro al di fuori -- al massimo sovrascriveremo
	     * i dati più vecchi con nuovi dati.
	     */
		int t = 0, testaSR = 0;
		
		int[] output = new int[lung_canale];
		
		/* 
		 * Processo di codifica:
		 * Calcolo degli output dei sommatori modulo 2, un bit alla volta 
		 */
		for (int i = 0; i < arrayNonCodificato.length; i++) {
			
			int j;
			shiftRegister[testaSR] = arrayNonCodificato[i];

			for (j = 0; j < xor.length; j++)
				xor[j] = 0;

			for (j = 0; j < M ; j++) {
				
				int k = (j + testaSR) % M;
				
				for (int ix = 0; ix < xor.length; ix++)
					xor[ix] ^= shiftRegister[k] & poli[ix][j];
						
			}
			
			//Scrittura degli output delle porte XOR
			for (j = 0; j < xor.length; j++)
				output[t++] = xor[j];

			//Shift a destra, prestando cura nel rispettare il modulo m
			if (--testaSR < 0)
				testaSR = KAPPA;
			
		}
		
		return output;
		
	}

	public int getLung_canale() { return lung_canale; }

}